5
\$\begingroup\$

I have successfully made a Perlin noise algorithm on the GPU. It works as expected, and generates great results. Now, as part of the physics calculations in my game, I need to replicate the exact same algorithm on the CPU, so that I can (given an X, Y and Z coordinate) determine whether or not that is inside a wall, or a walkable area.

I have debugged the shader through PIX, and I've gotten everything almost right, except for the part below (seen in shader code).

GPU (shader) code (HLSL)

float4 perm2d(float2 p)
{
    return tex2D(permSampler2d, p);
}

permSampler2d samples a texture that I generate out of Color structures and then pump to the GPU. The way I generate the texture on the CPU is the following:

CPU code (XNA C#)

int createPerm2d(int i)
{
    return permutation[i % 256];
}

public Texture2D GeneratePermTexture2d()
{
    permTexture2d = new Texture2D(device, 256, 256, true, SurfaceFormat.Color);
    permutationData = new Color[256 * 256];
    for (int x = 0; x < 256; x++)
    {
        for (int y = 0; y < 256; y++)
        {
            int A = createPerm2d(x) + y;
            int AA = createPerm2d(A);
            int AB = createPerm2d(A + 1);
            int B = createPerm2d(x + 1) + y;
            int BA = createPerm2d(B);
            int BB = createPerm2d(B + 1);
            permutationData[x + (y * 256)] = new Color((byte)(AA), (byte)(AB),
                                            (byte)(BA), (byte)(BB));
        }
    }
    permTexture2d.SetData<Color>(permutationData);
    return permTexture2d;
}

As said before, all this works as expected, until I run the code on the CPU to get the noise data back later.

According to PIX, the part that fails is indeed perm2d on the CPU (as seen below), which produces incorrect results.

CPU code (XNA C#)

static Vector4 perm2d(Vector2 p)
{
    return permutationData[(int)p.X + ((int)(p.Y) * 256)].ToVector4();
}

At the particular area (in the exact same pixel with the exact same seed used to generate the map, where it returns the incorrect results, PIX reports that the GPU returns "{0.035, 0.067, 0.365, 0.408}" from the perm2d function whereas the CPU code returns "{X:0,7450981 Y:0,345098 Z:0,5137255 W:0,09803922}".

Other than that, the rest of the functions produce the right outputs.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Are your vector x/y values that you're passing to perm2d always integers? On the GPU that will interpolate, on the CPU you're truncating and always getting an exact value.

(This also doesn't look like Perlin noise.)

\$\endgroup\$
4
  • \$\begingroup\$ Aha! Now that's very interesting. Can I turn off interpolation on the GPU? And yes, it is indeed Perlin Noise. \$\endgroup\$ Commented Aug 7, 2011 at 11:37
  • \$\begingroup\$ @Mathias You can turn off interpolation during texture sampling by using SamplerState.PointClamp or PointWrap. \$\endgroup\$ Commented Aug 7, 2011 at 12:24
  • \$\begingroup\$ Turning off interpolation on the GPU makes weird-shaped patterns in the map. And using interpolation on the GPU (as seen here stackoverflow.com/questions/6972652/…) will not work. Could it be because everything is rendered as colors with alpha, and when the GPU reads it, it can only read RGB? \$\endgroup\$ Commented Aug 7, 2011 at 12:59
  • \$\begingroup\$ Note that neither Perlin noise nor improved Perlin noise requires GPU interpolation to generate the gradients correctly; your code really looks like some kind of value noise, in which case you should get accurate results doing the same bilerp on the CPU. Nothing in your example is getting rendered, so I don't know what your last sentence refers to. Do you mean your texture format might different dramatically, RGBA on the CPU but something else on the GPU? I suppose, but I can't tell you if that's the case. \$\endgroup\$
    – user744
    Commented Aug 7, 2011 at 13:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .